package com.example.springsecuritydemo.filter;

import com.example.springsecuritydemo.entities.SecurityUser;
import com.example.springsecuritydemo.security.TokenManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Description:
 *
 * @author liuziyang
 * @date 2021/6/24 23:22
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private final TokenManager tokenManager;
    private final AuthenticationManager authenticationManager;
    private final ObjectMapper jsonMapper;

    public TokenLoginFilter(AuthenticationManager manager, TokenManager tokenManager) {
        super();
        this.authenticationManager = manager;
        this.tokenManager = tokenManager;
        this.jsonMapper = new ObjectMapper();
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        String username = obtainUsername(request);
        String password = obtainPassword(request);

        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return authenticationManager.authenticate(authRequest);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        final SecurityUser user = (SecurityUser) authResult.getPrincipal();
        final String token = tokenManager.createToken(user);
        Map<String, String> result = new LinkedHashMap<>();
        result.put("token", token);
        response.getWriter().print(jsonMapper.writeValueAsString(result));
        response.getWriter().flush();

        SecurityContextHolder.getContext().setAuthentication(authResult);

        getRememberMeServices().loginSuccess(request, response, authResult);

        // Fire event
        if (this.eventPublisher != null) {
            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
                    authResult, this.getClass()));
        }
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        super.unsuccessfulAuthentication(request, response, failed);
    }
}
